package com.lam.common.components.dict.interceptor;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.lam.common.components.dict.constant.DictConstant;
import com.lam.common.components.redis.RedisUtil;
import com.lam.common.utils.CollectionUtil;
import com.lam.common.utils.sql.SqlUtil;

/**
 * 默认情况下，MyBatis 允许使用插件来拦截的方法调用包括：
 *
 * Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
 * ParameterHandler (getParameterObject, setParameters)
 * ResultSetHandler (handleResultSets, handleOutputParameters)
 * StatementHandler (prepare, parameterize, batch, update, query)
 */
//method = "update"则能拦截insert、update、delete的方法
@Intercepts({
    @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
@Component
public class DictMybatisInterceptor implements Interceptor {
	
	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	
	protected static Set<String> tableNameSet = new HashSet<>(); 
    
	@Override
    public Object intercept(Invocation invocation) throws Throwable {
        
        Object result = invocation.proceed();
        
        // 获取 MappedStatement对象 和 参数对象
        MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
        // 获取到拥有占位符的sql语句
        String sql = ms.getBoundSql(invocation.getArgs()[1]).getSql();
        // sql命令类型
        SqlCommandType sqlCommandType = ms.getSqlCommandType();
        switch (sqlCommandType) {
	        case INSERT:
	        case UPDATE:
	        case DELETE:{
	        	if(result instanceof Number) {
	            	if(((Number)result).intValue() > 0) {
	            		clearCache(sqlCommandType, sql);
	            	}
	            }else {
	            	clearCache(sqlCommandType, sql);
	            }
	        }
	        default:break;
        }
        
        return result;
    }
    
    private void clearCache(SqlCommandType sqlCommandType, String sql) {
    	try {
    		List<String> tableList = SqlUtil.getTableNameBySql(sql);
            if(CollectionUtil.isNotEmpty(tableList)) {
            	for (String tableName : tableList) {
            		if(tableNameSet.contains(tableName)) {
            			logger.info("表【{}】的 {} 操作触发【自定义字典数据】的缓存清理！", tableName, sqlCommandType);
                		RedisUtil.removeAll(DictConstant.SYS_TABLE_DICT_PREFIX + tableName);
                	}
				}
            }
    	} catch (Exception e) {
            logger.error("【自定义字典数据】缓存自动清理异常", e);
        }
    }

}
